iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
自我挑戰組

30 天工程師雜學之旅系列 第 14

k8s雜記-2 Kubernetes 調度進階指南:Taints、Tolerations 與 Affinity

  • 分享至 

  • xImage
  •  

從 NodeSelector 的限制,到更靈活的三劍客
restaurant

1. 前言 — 從實務痛點開始

最近在管理 Kubernetes 時,我遇到一個很典型的問題:

  • GPU 節點被一些「不需要 GPU」的 Pod 佔用,真正需要 GPU 的 AI 任務卻排不上去。
  • 測試環境的 Pod 一不小心被排到生產節點,影響線上服務。
  • 多副本的服務被全部排到同一台 Node,一台 Node 掛掉整個服務也一起倒。

剛開始,我用的都是最簡單的 NodeSelector 來解決調度問題:

nodeSelector:
  disktype: ssd

只要給 Node 打上標籤,再讓 Pod 指定這個標籤,Pod 就會乖乖地排到符合條件的 Node 上。

但是,這種方法在實務上很快就遇到瓶頸:

  1. 太硬性 — 不符合就直接 Pending,沒有退一步的「偏好」或「次佳方案」。
  2. 無法防守 — Node 無法主動拒絕不該來的 Pod,只能被動等 Pod 來挑自己。
  3. 無法控制 Pod 與 Pod 的關係 — 無法做到「同桌」或「不要同桌」的規則。

這時,我才開始深入研究 Kubernetes 的調度三劍客:
Taints、Tolerations、Affinity


2. 餐廳比喻 — 座位與顧客

想像 Kubernetes 集群是一間餐廳:

  • Node = 餐廳的座位區,每張桌子可能有不同特色(窗邊、VIP 包廂、可帶寵物…)。
  • Pod = 來用餐的顧客,每個顧客有自己的需求(喜歡窗邊、不能坐戶外、帶寵物…)。
  • NodeSelector = 顧客直接說「我要坐窗邊桌」,餐廳安排符合條件的桌子。

問題是:

  • 餐廳無法主動拒絕顧客(Node 不能排斥 Pod)。
  • 顧客只能做硬性選擇(沒有「偏好」或「建議」)。
  • 無法處理「要跟朋友一起坐」或「不要跟陌生人坐」的情況。

這時就需要進階的規則:

  • Taints:餐桌上的「限制告示牌」
  • Tolerations:顧客的「通行證」
  • Affinity:顧客的「座位喜好」

3. Taints — 餐桌的限制告示牌

Taint 是 Node 主動排斥 Pod 的方法。
它會在 Node 上貼一個「告示牌」,沒有符合條件的 Pod 就不能坐下。

格式:

kubectl taint nodes <node-name> key=value:Effect

三種 Effect:

  • NoSchedule:沒有證明的顧客不安排座位
  • PreferNoSchedule:盡量不安排,但必要時會安排
  • NoExecute:已經坐下的顧客如果不符合條件,要請他離開

範例:給 GPU 節點加上 Taint

kubectl taint nodes gpu-node gpu=true:NoSchedule

這代表這張「GPU 座位」貼上了告示牌:

只有持 GPU 證明的顧客可以坐


4. Tolerations — 顧客的通行證

Toleration 是 Pod 上的通行證,用來容忍特定的 Taint。
有這張證明的 Pod,才能坐到被 Taint 限制的 Node。

範例:Pod 帶上 GPU 通行證

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  tolerations:
  - key: "gpu"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"

這就像顧客拿著「GPU 卡」,服務員會讓他坐在貼了「僅限 GPU」的桌子上。


5. Affinity — 顧客的座位喜好

Affinity 是 Pod 的座位偏好
它可以控制 Pod 傾向去哪個 Node,或是跟哪些 Pod 在一起。

分成三種:

  1. Node Affinity(Node 偏好)
    • 例如:只坐窗邊桌(有特定標籤的 Node)
    • 支援硬性 (requiredDuringSchedulingIgnoredDuringExecution) 與偏好 (preferredDuringSchedulingIgnoredDuringExecution)
  2. Pod Affinity(想跟朋友同桌)
    • 例如:Web Pod 想跟 Cache Pod 坐一起
  3. Pod Anti-Affinity(不要跟某些人同桌)
    • 例如:多副本要分散在不同 Node

範例:Node Affinity

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: disktype
          operator: In
          values:
          - ssd

這表示顧客(Pod)必須坐在有 disktype=ssd 的桌子(Node)。


6. 實務應用案例

案例 1:保護 GPU 節點

問題:開發人員不小心把非 GPU 工作丟到 GPU 節點上。
解法

  • GPU 節點加上 Taint gpu=true:NoSchedule
  • AI 工作 Pod 加上對應的 Toleration
  • 非 GPU Pod 無法誤排上 GPU 節點

案例 2:隔離測試與生產

問題:測試服務誤上生產節點。
解法

  • 生產節點加上 Taint env=prod:NoSchedule
  • 生產服務 Pod 加上 Toleration
  • 測試服務沒有 Toleration → 不會排到生產節點

案例 3:多副本高可用

問題:三個副本都排在同一台 Node,掛了就全掛。
解法

  • 使用 Pod Anti-Affinity,要求副本分散在不同 Node。
podAntiAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
  - labelSelector:
      matchExpressions:
      - key: app
        operator: In
        values:
        - my-service
    topologyKey: "kubernetes.io/hostname"

案例 4:數據局部性

問題:Web Pod 與 Cache Pod 分開部署,性能下降。
解法

  • 使用 Pod Affinity,要求 Web 與 Cache 同 Node。

7. Taints/Tolerations vs Affinity — 核心差異

機制 調度方向 用途 比喻
Taints Node → Pod 排斥不符合的 Pod 餐桌貼告示牌
Tolerations Pod → Node 允許坐有限制的桌子 顧客通行證
Affinity Pod → Node/Pod 偏好或要求位置 顧客座位喜好

8. 注意事項

  • Taint 太嚴 → Pod 可能永遠 Pending
  • Affinity 過於嚴格 → 也可能導致無法調度
  • 實務上通常會結合使用
    • 先用 Taint 保護資源
    • 再用 Affinity 優化位置

9. 結語

NodeSelector 是調度的入門方法,但它像一條直線,缺乏彈性。
Taints / Tolerations / Affinity 則像餐廳的座位規則與顧客喜好,能讓資源利用率更高、服務更穩定。

當你下次遇到 Pod 排不上去,或資源被亂用的情況,不妨想想:
是不是該貼一張告示牌(Taint)、發一張通行證(Toleration)、或幫顧客安排更合適的座位(Affinity)?


上一篇
k8s雜記-1 Kubernetes 管理資源的兩種方式:Imperative vs Declarative
下一篇
k8s雜記-3 Kubernetes Scheduler Profiles 與 Extension Points 實際案例解析
系列文
30 天工程師雜學之旅22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言